import { useRef } from 'react';

type Action = () => void;
export const useContinuousAction = (
  action: Action,
  options: {
    /** 触发间隔 */
    baseInterval?: number;
    /** 加速间隔步长 ms */
    speedIncreaseStep?: number;
    /** 用于区分点击和按住的延迟时间 */
    holdThreshold?: number;
    /** 最大加速因子 */
    maxSpeedFactor?: number;
  } = {},
) => {
  const {
    baseInterval = 200,
    speedIncreaseStep = 500,
    maxSpeedFactor = 10,
    holdThreshold = 150,
  } = options;

  const speedFactor = useRef(1);

  const isSingleClickProcessed = useRef(true);

  const actionTimer = useRef<NodeJS.Timeout>();

  const speedTimer = useRef<NodeJS.Timeout>();

  const singleTimer = useRef<NodeJS.Timeout>();

  const clearAllTimer = () => {
    clearInterval(actionTimer.current);
    clearInterval(speedTimer.current);
    clearTimeout(singleTimer.current);
  };

  /**
   * 执行连续事件
   */
  const onStartContinuousAction = (action: Action) => {
    action();

    clearAllTimer();

    isSingleClickProcessed.current = true;

    actionTimer.current = setInterval(
      action,
      baseInterval / speedFactor.current,
    );

    speedTimer.current = setInterval(() => {
      if (speedFactor.current < maxSpeedFactor) {
        speedFactor.current += 0.5;
        // 清除定时器重新开始加速
        clearInterval(actionTimer.current);
        actionTimer.current = setInterval(
          action,
          baseInterval / speedFactor.current,
        );
      }
    }, speedIncreaseStep);
  };

  /**
   * 停止连续事件
   */
  const onStopContinuousAction = () => {
    clearAllTimer();

    speedFactor.current = 1;
    isSingleClickProcessed.current = true;
  };

  const onMouseDown = () => {
    isSingleClickProcessed.current = false;

    action();

    clearTimeout(singleTimer.current);
    singleTimer.current = setTimeout(() => {
      if (!isSingleClickProcessed.current) {
        onStartContinuousAction(action);
      }
    }, holdThreshold);
  };

  const onMouseUp = () => {
    onStopContinuousAction();
  };

  const onTouchStart = () => {
    isSingleClickProcessed.current = false;

    action();

    clearTimeout(singleTimer.current);
    singleTimer.current = setTimeout(() => {
      if (!isSingleClickProcessed.current) {
        onStartContinuousAction(action);
      }
    }, holdThreshold);
  };

  const onTouchEnd = () => {
    onStopContinuousAction();
  };

  return {
    onMouseDown,
    onMouseUp,
    onTouchStart,
    onTouchEnd,
  };
};
